package persistence;

import java.util.Date;
import java.util.Iterator;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.constraints.NotNull;

import business.validation.ValidationException;


final public class Subscription {
	private int id=0;
	private String subscriptionNo;
	@NotNull
	private Supplier supplier;
	@NotNull
	private PredefinedEntry status;
	private float currentPrice;
	private float previousPrice;
	private String internalLocation;
	/** the subsidiary of the FH JOANNEUM the subscription belongs to*/
	@NotNull
	private LibraryLocation location;
	@NotNull
	private PredefinedEntry kindOfAcquisition;
	@NotNull
	private Date orderingDate;
	private Date startDate;
	private Date currentIssueDate;	
	private Date endDate;
	private Date paidUntil;
	private String cancellationPeriod;
	private Boolean onlineInAleph;
	//TODO: validation: costUnit and Purchaser must match the LibraryLocation
	@NotNull
	private CostUnit costUnit;
	@NotNull
	private Purchaser purchaser;
	private BindingDetails bookbindingDetails;
	private String signature;
	private String barcode;
	private String notes;
	private String onlineNotes;
	private PredefinedEntry currency;
	private PredefinedEntry kindOfStorage;
	private Periodical periodical;
	private int reminderFrequency;
	
	private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
	
	public Subscription() {
	}
	
	public Subscription(int id) {
		this();
		this.id=id;
	}

	protected Subscription(int id, String subscrNo, PredefinedEntry status, float currpr, float prevpr, Date startDate,
							Date endDate, String intLoc, Date paidUntil, String cancelp, Boolean onlineal, String sign,
							Date orderd, String bc, Date curissd, PredefinedEntry kindofac, String note,
							String onote, PredefinedEntry curr, PredefinedEntry kos, LibraryLocation loc,Supplier sup,
							CostUnit cu, Purchaser puc, Periodical per, BindingDetails bbdet, int reminderFrequency) throws RuntimeException{
		this();	
		this.setId(id);
		this.setSubscriptionNo(subscrNo);
		this.setSupplier(sup);
		this.setStatus(status);
		this.setCurrentPrice(currpr);
		this.setPreviousPrice(prevpr);
		this.setInternalLocation(intLoc);
		this.setLocation(loc);
		this.setKindOfAcquisition(kindofac);
		this.setOrderingDate(orderd);
		this.setStartDate(startDate);
		this.setCurrentIssueDate(curissd);
		this.setEndDate(endDate);
		this.setPaidUntil(paidUntil);
		this.setCancellationPeriod(cancelp);
		this.setOnlineInAleph(onlineal);
		this.setCostUnit(cu);
		this.setPurchaser(puc);
		this.setBookbindingDetails(bbdet);
		this.setSignature(sign);
		this.setBarcode(bc);
		this.setNotes(note);
		this.setOnlineNotes(onote);
		this.setCurrency(curr);
		this.setKindOfStorage(kos);
		this.setPeriodical(per);
		this.setReminderFrequency(reminderFrequency);		
	}
	
	protected Subscription(Subscription sub) throws ValidationException {
		this();
		this.setId(sub.getId());
		this.setSubscriptionNo(sub.getSubscriptionNo());
		this.setSupplier(sub.getSupplier());
		this.setStatus(sub.getStatus());
		this.setCurrentPrice(sub.getCurrentPrice());
		this.setPreviousPrice(sub.getPreviousPrice());
		this.setInternalLocation(sub.getInternalLocation());
		this.setLocation(sub.getLocation());
		this.setKindOfAcquisition(sub.getKindOfAcquisition());
		this.setOrderingDate(sub.getOrderingDate());
		this.setStartDate(sub.getStartDate());
		this.setCurrentIssueDate(sub.getCurrentIssueDate());
		this.setEndDate(sub.getEndDate());
		this.setPaidUntil(sub.getPaidUntil());
		this.setCancellationPeriod(sub.getCancellationPeriod());
		this.setOnlineInAleph(sub.isOnlineInAleph());
		this.setCostUnit(sub.getCostUnit());
		this.setPurchaser(sub.getPurchaser());
		this.setBookbindingDetails(sub.getBookbindingDetails());
		this.setSignature(sub.getSignature());
		this.setBarcode(sub.getBarcode());
		this.setNotes(sub.getNotes());
		this.setOnlineNotes(sub.getOnlineNotes());
		this.setCurrency(sub.getCurrency());
		this.setKindOfStorage(sub.getKindOfStorage());
		this.setPeriodical(sub.getPeriodical());
		this.setReminderFrequency(sub.getReminderFrequency());
		
		Set<ConstraintViolation<Subscription>> violations = validator.validate(this);
		if (violations.size()>0) {
			StringBuilder sbuilder = new StringBuilder();
			Iterator<ConstraintViolation<Subscription>> it = violations.iterator();
			
			sbuilder.append("Invalid values: ");
			while (it.hasNext()) {
				ConstraintViolation<Subscription> currentViolation = it.next();
				sbuilder.append("Invalid value: " + currentViolation.getInvalidValue() +
								" - " + currentViolation.getMessage() + "\n");
			}
			throw new ValidationException(sbuilder.toString());
		}
	}
	
	@Override
	public boolean equals (Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj==null || obj.getClass()!=this.getClass()) {
			return false;
		}
		Subscription comp = (Subscription) obj;
		if (this.id != comp.getId()) {
			return false;
		}
		if (this.location == null) {
			if (comp.getLocation()!=null)
				return false;
		}
		else {
			if (!this.location.equals(comp.getLocation()))
				return false;
		}
		if (this.periodical == null) {
			if (comp.getPeriodical() != null)
				return false;
		}
		else {
			if (!this.periodical.equals(comp.getPeriodical()))
				return false;			
		}
		return true;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id;
		result = prime * result
				+ ((location == null) ? 0 : location.hashCode());
		result = prime * result
				+ ((periodical == null) ? 0 : periodical.hashCode());
		return result;
	}	
	
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("Subscription: id=").append(id).append(", subscriptionNo=").append(subscriptionNo).
			    append(", supplier=").append(supplier).append(", status=").append(status).
			    append(", currentPrice=").append(currentPrice).append(", previousPrice=").append(previousPrice).
			    append(", internalLocation=").append(internalLocation).append(", location=").append(location).
			    append(", kindOfAcquisition=").append(kindOfAcquisition).append(", orderingDate=").append(orderingDate).
			    append(", startDate").append(startDate).append(", currentIssueDate=").append(currentIssueDate).
			    append(", endDate=").append(endDate).append("paidUntil=").append(paidUntil).append(", cancellationPeriod=").append(cancellationPeriod).
			    append(", onlineInAleph=").append(onlineInAleph).append(", costUnit=").append(costUnit).
			    append(", purchaser=").append(purchaser).append("bookbindingDetails=").append(bookbindingDetails).append(", signature=").append(signature).
			    append(", barcode=").append(barcode).append(", notes=").append(notes).append(", online notes=").append(onlineNotes).
			    append(", currency=").append(currency).append(", kind of storage=").append(kindOfStorage).
			    append(", periodical=").append(periodical).append(", reminderFrequency=").append(reminderFrequency);
		return builder.toString();
	}
	
	public int getId() {
		return id;
	}

	public String getSubscriptionNo() {
		return this.subscriptionNo;
	}

	public Supplier getSupplier() {
		return this.supplier;
	}
	
	public PredefinedEntry getStatus() {
		return this.status;
	}
	public float getCurrentPrice() {
		return this.currentPrice;
	}
	public float getPreviousPrice() {
		return this.previousPrice;
	}
	public String getInternalLocation() {
		return this.internalLocation;
	}

	public PredefinedEntry getKindOfAcquisition() {
		return this.kindOfAcquisition;
	}

	
	public LibraryLocation getLocation() {
		return this.location;
	}
	
	public Date getOrderingDate() {
		return this.orderingDate;
	}

	
	public Date getStartDate() {
		return this.startDate;
	}

	
	public Date getCurrentIssueDate() {
		return this.currentIssueDate;
	}

	
	public Date getEndDate() {
		return this.endDate;
	}

	
	public Date getPaidUntil() {
		return this.paidUntil;
	}

	
	public String getCancellationPeriod() {
		return this.cancellationPeriod;
	}

	
	public Boolean isOnlineInAleph() {
		return this.onlineInAleph;
	}

	
	public CostUnit getCostUnit() {
		return this.costUnit;
	}

	
	public Purchaser getPurchaser() {
		return this.purchaser;
	}

	
	public BindingDetails getBookbindingDetails() {
		return this.bookbindingDetails;
	}
	
	public String getSignature() {
		return this.signature;
	}

	
	public String getBarcode() {
		return this.barcode;
	}

	
	public String getNotes() {
		return this.notes;
	}

	
	public String getOnlineNotes() {
		return this.onlineNotes;
	}

	
	public PredefinedEntry getCurrency() {
		return this.currency;
	}

	
	public PredefinedEntry getKindOfStorage() {
		return this.kindOfStorage;
	}

	
	public Periodical getPeriodical() {
		return this.periodical;
	}
	
	public int getReminderFrequency() {
		return this.reminderFrequency;
	}
	
	public void setId(int id) {
//		ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
//		Validator validator = factory.getValidator();
//		Periodical p = new Periodical();
//		p.setId(id);
//		Set<ConstraintViolation<Periodical>> violations = validator.validate(p);
//		if(violations.size()==0)
//			this.id = id;
		this.id=id;
	}

	public void setSubscriptionNo(String subscriptionNo) {
		System.out.println("-----SubscriptionNo set from " + this.subscriptionNo);
		this.subscriptionNo = subscriptionNo;
		System.out.println(" to " + this.subscriptionNo);
		Set<ConstraintViolation<Subscription>> violations = validator.validateProperty(this, "subscriptionNo");
		if (violations.size()>0)
			System.out.println("------------------------------ illegalsubscriptonNo");
	}

	public void setSupplier(Supplier supplier) {
		this.supplier = supplier;
	}

	public void setStatus(PredefinedEntry status) {
		this.status = status;
	}

	public void setCurrentPrice(float currentPrice) {
		this.currentPrice = currentPrice;
	}

	public void setPreviousPrice(float previousPrice) {
		this.previousPrice = previousPrice;
	}

	public void setInternalLocation(String internalLocation) {
		this.internalLocation = internalLocation;
	}

	public void setLocation(LibraryLocation location) {
		this.location = location;
	}

	public void setKindOfAcquisition(PredefinedEntry kindOfAcquisition) {
		this.kindOfAcquisition = kindOfAcquisition;
	}

	public void setOrderingDate(Date orderingDate) {
		this.orderingDate = orderingDate;
	}

	public void setStartDate(Date startDate) {
		this.startDate = startDate;
	}

	public void setCurrentIssueDate(Date currentIssueDate) {
		this.currentIssueDate = currentIssueDate;
	}

	public void setEndDate(Date endDate) {
		this.endDate = endDate;
	}

	public void setPaidUntil(Date paidUntil) {
		this.paidUntil = paidUntil;
	}

	public void setCancellationPeriod(String cancellationPeriod) {
		this.cancellationPeriod = cancellationPeriod;
	}

	public void setOnlineInAleph(Boolean onlineInAleph) {
		this.onlineInAleph = onlineInAleph;
	}

	public void setCostUnit(CostUnit costUnit) {
		this.costUnit = costUnit;
	}

	public void setPurchaser(Purchaser purchaser) {
		this.purchaser = purchaser;
	}

	public void setBookbindingDetails(BindingDetails bookbindingDetails) {
		this.bookbindingDetails = bookbindingDetails;
	}

	public void setSignature(String signature) {
		this.signature = signature;
	}

	public void setBarcode(String barcode) {
		this.barcode = barcode;
	}

	public void setNotes(String notes) {
		this.notes = notes;
	}

	public void setOnlineNotes(String onlineNotes) {
		this.onlineNotes = onlineNotes;
	}

	public void setCurrency(PredefinedEntry currency) {
		this.currency = currency;
	}

	public void setKindOfStorage(PredefinedEntry kindOfStorage) {
		this.kindOfStorage = kindOfStorage;
	}

	public void setPeriodical(Periodical periodical) {
		this.periodical = periodical;
	}
	
	public void setReminderFrequency(int reminderFrequency) {
		this.reminderFrequency = reminderFrequency;
	}
}
